estimateCostOfDebt<-function(inData=yieldData,minConstraint=NULL ,
                             maxConstraint=NULL) {
  #inData=tempData; minConstraint<-maxConstraint<-NULL
  # functions checking inData
  dNames<-names(inData)
  dMatch<-match(dNames,c("tenor","yield","faceValue"))
  missingName<-is.na(dMatch)
  if(sum(missingName)>0) {
    stop("You are missing one of: \"tenor\"; \"yield\"; \"faceValue\"\n")
  }
  missingNumeric<-!apply(inData,2,is.numeric)
  if(sum(missingNumeric)>0) {
    stop("Your data are not all numeric\n")
  }
  
  # other logical checks ...

  # set constraints if NULL
  if(is.null(minConstraint)) {
    minConstraint<-c( 0,-15,-30,-30, 0,2.5,0)
    maxConstraint<-c(15, 30, 30, 30, 2.5, 5,30)
    minConstraintNS<-minConstraint[c(1:3,5)]
    maxConstraintNS<-maxConstraint[c(1:3,5)]
  }else{
    if(length(minConstraint)!=6) {
      stop("You have not specified a minConstraint of six parameters\n
corresponding to {B0;B1;B2;B3;Lambda1;Lambda2} of the\n
NSS model\n")
    }
    minConstraintNS<-minConstraint[c(1:3,5)]
    maxConstraintNS<-maxConstraint[c(1:3,5)]
  }
 
  # define metaparameters of the solution
  algo <- list(nP = 100L,
               nG = 500L,
               F = 0.50,
               CR = 0.99,
               min = minConstraint,
               max = maxConstraint,
               pen = penalty,
               repair = NULL,
               loopOF = TRUE,
               loopPen = FALSE,
               loopRepair = TRUE,
               printBar = FALSE,
               printDetail = FALSE)
  
  # define data object with constraints
  inData$weights<-inData$faceValue/sum(inData$faceValue)
  
  dataObject <- list(yM = inData$yield,
                  tm = inData$tenor,
                  model = NSS,
                  min = minConstraint,
                  max = maxConstraint,
                  ww = 1,
                  weighting = inData$weights)

  # calculate kernel estimate weighted by face value
  costOfDebtKernel<-sm::sm.regression(inData$tenor,inData$yield ,h=1.5,
                    weights=inData$faceValue,display="none",
                    eval.points=10)$estimate
  
  # calculate NSS estimate
  solNSS <- NMOF::DEopt(OF = OF, algo = algo, data = dataObject)
  
  costOfDebtNSS<-NMOF::NSS(solNSS$xbest,10)
  
  # dataObject$model <- NS
  inDataOrder<-order(inData$tenor)
  
  # solNS <- NMOF::DEopt(OF = OF, algo = algo, data = dataObject)
  solNS<-YieldCurve::Nelson.Siegel( inData$yield[inDataOrder], inData$tenor[inDataOrder] )
  solNS[4]<-1/solNS[4]
  solNS<-as.numeric(solNS)
  # sum((yieldData$yield - NS(test,yieldData$tenor))^2)
  # 
  costOfDebtNS<-NMOF::NS(solNS,10)
  OFvalueNS<-sum((inData$yield - NMOF::NS(solNS,inData$tenor))^2)
  # return cost of debt estimates
  solutions<-c(costOfDebtKernel,costOfDebtNS,costOfDebtNSS)
  names(solutions) <-c("kernel","NS","NSS")
  objective<-c(NS=OFvalueNS,NSS=solNSS$OFvalue)
  list(solutions=solutions,objective=objective,
              NSparameters=solNS,NSSparameters=solNSS$xbest)
  # rm(inData,missingNumeric,missingName,objective,solutions,OFvalueNS,
  # costOfDebtKernel,costOfDebtNS,costOfDebtNSS,solNS,solNSS,dataObject,
  # algo,minConstraint,maxConstraint,dNames,dMatch)
}
#test<-estimateCostOfDebt()

### penalty function for DEOpt
penalty <- function(mP, data) {
  minV <- data$min
  maxV <- data$max
  ww <- data$ww
  
  ## if larger than maxV, element in A is positiv
  A <- mP - as.vector(maxV)
  A <- A + abs(A)
  
  ## if smaller than minV, element in B is positiv
  B <- as.vector(minV) - mP
  B <- B + abs(B)
  ## beta 1 + beta2 > 0
  C <- ww*((mP[1L, ] + mP[2L, ]) - abs(mP[1L, ] + mP[2L, ]))
  A <- ww * colSums(A + B) - C
  A
}

# Objective function for DEOpt
OF <- function(param,data) {
  y <- data$model(param,data$tm)
  aux <- (y - data$yM)^2
  res <- sum(aux)
  # aux <- y - data$yM
  # res <- max(abs(aux))
  
  ## compute the penalty
  aux <- y - abs(y) ## aux == zero for nonnegative y
  aux <- -sum(aux) * data$ww
  res <- res + aux
  if (is.na(res)) {
    res <- 1e10
  }else{
    #res<-sum(res*data$weighting)
    res<-sum(res)
    
      }
  res
}

# measure support: kernel density centred on target tenor
measureSupport<-function(inData=yieldData$tenor,h=1.5,targetTenor=10) {
  sum(dnorm(inData,mean=targetTenor,sd=h))
}
#measureSupport()


  
